package com.taillive.core.web;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

import org.apache.commons.beanutils.ConvertUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;


import com.opensymphony.xwork2.Preparable;
import com.taillive.core.dao.EntityDao;
import com.taillive.core.dao.support.Page;
import com.taillive.core.exception.BusinessException;
import com.taillive.core.utils.BeanUtils;
import com.taillive.core.utils.GenericsUtils;


public abstract class StrutsEntityAction<T, M extends EntityDao<T>> extends
		StrutsAction implements InitializingBean, Preparable {

	// protected static final String LIST = "list";

	protected Class<T> entityClass; 

	protected Class idClass;
	protected String idName; 
	private M entityManager; 


	// All Entities
	private Collection<T> items;

	public Collection<T> getItems() {
		return items;
	}
	
	public void setItems(Collection<T> items) {
		this.items = items;
	}
	

	// Single Entity
	private T item;

	public T getItem() {
		return item;
	}

	public void setItem(T item) {
		this.item = item;
	}

	//Entity ID
	
	private String id;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	//Multi Entity ID
	private String[] ids;

	public String[] getIds() {
		return ids;
	}

	public void setIds(String[] ids) {
		this.ids = ids;
	}


	protected Class<T> getEntityClass() {
		return entityClass;
	}


	protected M getEntityManager() {
		Assert.notNull(entityManager, "Manager");
		return entityManager;
	}


	@SuppressWarnings("unchecked")
	public void afterPropertiesSet() {
		
		entityClass = GenericsUtils.getSuperClassGenricType(getClass());

		
		List<Field> fields = BeanUtils.getFieldsByType(this, GenericsUtils
				.getSuperClassGenricType(getClass(), 1));

		Assert.isTrue(fields.size() == 1,
				"subclass's has not only one entity manager property.");
		try {
			entityManager = (M) BeanUtils.forceGetProperty(this, fields.get(0)
					.getName());
			Assert.notNull(entityManager,
					"subclass not inject manager to action sucessful.");
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
		try {
			idName = entityManager.getIdName(entityClass);
			idClass = BeanUtils.getPropertyType(entityClass, idName);
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
	}


	/*
	 * protected String getEntityName() { return
	 * StringUtils.uncapitalize(ClassUtils.getShortName(getEntityClass())); }
	 */


	/*
	 * protected String getEntityListName() { return
	 * StringUtils.uncapitalize(ClassUtils.getShortName(getEntityClass()))+ "s"; }
	 */

	// -------------------------------------------------------------
	/**
	 * List all entities
	 * 
	 * @throws Exception
	 */
	public String list() throws Exception {
		items = listEntity();
		return SUCCESS;
	}

	/**
	 * 
	 * Paged entities
	 * @throws Exception 
	 * 
	 * @throws Exception
	 */
	public String pagedQuery() throws Exception  {
		
		
		setP(getEntityManager().getPage(getPage(), 15));
		
		afterPagedQuery();
		return SUCCESS;
	}

	/**
	 * 
	 */
	public String edit() throws Exception {
		afterEdit();
		return SUCCESS;
	}

	/**
	 * view
	 */
	public String view() {

		return SUCCESS;
	}

	public void prepare() throws Exception {
		
		//String uri = getRequest().getRequestURI();
		
		
		
		Serializable sid = getEntityId();
		T object = null;

		if (sid != null) {
			object = getEntity(sid);
		}
		
		if (object != null) {
			item = object;
		} else {
			item = entityClass.newInstance();
		}
		
		afterPrepare();
		
		
	}

	/**
	 * save
	 */

	public String save() throws Exception {
		try {
			
			beforeSave();
			saveEntity(item);

		} catch (BusinessException e) {
			
		}
		
		afterSave();

		return SUCCESS;
	}

	/**
	 * delete one Entity
	 */
	public String delete() {
		try {
			if (ids != null) {
				for (String i : ids) {
					deleteEntity(getEntityId(i));
				}
			} else if(id!=null&&!"".equals(id)){
				deleteEntity(getEntityId());
			}
		} catch (Exception e) {
			e.printStackTrace();

		}
		
		afterDelete();
		return SUCCESS;
	}


	protected List<T> listEntity() {
		return getEntityManager().getAll();
	}


	protected T getEntity(Serializable id) {
		
		return getEntityManager().get(id);
	}


	protected void saveEntity(T object) {
		getEntityManager().save(object);
	}

	/**
	 * Delete by ID
	 */
	protected void deleteEntity(Serializable id) {
		getEntityManager().removeById(id);
		
	}

	/**
	 * 
	 */
	protected void deleteEntity(T t) {
		getEntityManager().remove(t);
	}


	protected Serializable getEntityId() {
		return getEntityId(id);
	}

	protected Serializable getEntityId(String id) {
		try {
			if (id == null || "".equals(id)) {
				return null;
			} else {
				Serializable sid = (Serializable) ConvertUtils.convert(id,
						idClass);
				return sid;
			}

		} catch (NumberFormatException e) {
			throw new IllegalArgumentException("Wrong when get id from request");
		}
	}
	
	protected void beforeSave(){};
	
	protected void afterPagedQuery(){};
	
	protected void afterEdit(){};
	
	protected void afterDelete(){};
	
	protected void afterSave(){}
	
	protected void afterPrepare(){};




}
